﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Text;
using System.Windows.Forms;

namespace Workflows.Components.Rules
{
    public partial class ClassRuleConditionEditor : Form
    {
        public event RuleDataUpdated OnRuleConditionUpdated;
        private object _OwnerRuleNode;
        private Rule _Rule;
        private ClassRuleCondition _ClassRule;
        private Dictionary<string, string> _AssemblyFilePaths;
        private Dictionary<string, string> _TypeFullNames;

        /// <summary>
        /// 
        /// </summary>
        public ClassRuleConditionEditor()
        {
            InitializeComponent();
        }

        /// <summary>
        /// bind rule node data 
        /// </summary>
        /// <param name="ownerRuleNode"></param>
        /// <param name="rule"></param>
        /// <param name="condition"></param>
        public void InitRuleCondition(object ownerRuleNode, Rule rule, ClassRuleCondition condition)
        {
            this._OwnerRuleNode = ownerRuleNode;
            this._Rule = rule;
            this._ClassRule = condition;
            this.DisplaySettings();
        }


        /// <summary>
        /// 
        /// </summary>
        public void DisplaySettings()
        {
            if (!string.IsNullOrEmpty(this._ClassRule.AssemblyFilePath))
            {
                for (int i = 0; i < this.cbo_Assemblies.Items.Count; i++)
                {
                    if (this._AssemblyFilePaths[this.cbo_Assemblies.Items[i].ToString()] ==
                        this._ClassRule.AssemblyFilePath)
                    {
                        this.cbo_Assemblies.SelectedIndex = i;
                        break;
                    }
                }
            }

            if (!string.IsNullOrEmpty(this._ClassRule.ClassName))
            {
                for (int i = 0; i < this.cbo_EvaluatorClasses.Items.Count; i++)
                {
                    if (this._TypeFullNames[this.cbo_EvaluatorClasses.Items[i].ToString()] == this._ClassRule.ClassName)
                    {
                        this.cbo_EvaluatorClasses.SelectedIndex = i;
                        break;
                    }
                }
            }

            if (!string.IsNullOrEmpty(this._ClassRule.MethodName))
            {
                for (int i = 0; i < this.cbo_Methods.Items.Count; i++)
                {
                    if (this.cbo_Methods.Items[i].ToString() == this._ClassRule.MethodName)
                    {
                        this.cbo_Methods.SelectedIndex = i;
                        break;
                    }
                }
            }
        }

        private void ClassRuleConditionEditor_Load(object sender, EventArgs e)
        {
            this.PopulateAssemblies();
        }

        private void PopulateAssemblies()
        {
            string binFolderPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            DirectoryInfo binDirInfo = new DirectoryInfo(binFolderPath);
            FileInfo[] fileInfos = binDirInfo.GetFiles("*.dll", SearchOption.TopDirectoryOnly);
            this._AssemblyFilePaths = new Dictionary<string, string>();
            if (fileInfos != null && fileInfos.Length > 0)
            {
                foreach (FileInfo fileInfo in fileInfos)
                {
                    this._AssemblyFilePaths.Add(Path.GetFileNameWithoutExtension(fileInfo.FullName), fileInfo.FullName);
                }
            }
            this.cbo_Assemblies.Items.Clear();
            this.cbo_Assemblies.SelectedIndex = -1;
            this.cbo_Assemblies.Text = string.Empty;
            if (this._AssemblyFilePaths.Count > 0)
            {
                foreach (string fileName in this._AssemblyFilePaths.Keys)
                {
                    this.cbo_Assemblies.Items.Add(fileName);
                }
            }
        }

        private void PopulateClasses(string assemblyFilePath)
        {
            Assembly assem = Assembly.LoadFile(assemblyFilePath);
            Type[] types = assem.GetTypes();
            this._TypeFullNames=new Dictionary<string, string>();
            if(types !=null && types.Length>0)
            {
                foreach(Type type in types)
                {
                    this._TypeFullNames.Add(type.Name,type.FullName);
                }
            }
            this.cbo_EvaluatorClasses.Items.Clear();
            this.cbo_EvaluatorClasses.SelectedIndex = -1;
            this.cbo_EvaluatorClasses.Text = string.Empty;
            if(this._TypeFullNames.Count>0)
            {
                foreach(string name in this._TypeFullNames.Keys)
                {
                    this.cbo_EvaluatorClasses.Items.Add(name);
                }
            }
        }

        private void PopulateMethods(string assemblyFilePath, string typeFullName)
        {
            Assembly assem = Assembly.LoadFile(assemblyFilePath);
            Type type = assem.GetType(typeFullName);
            MethodInfo[] methods = type.GetMethods();
            this.cbo_Methods.Items.Clear();
            this.cbo_Methods.SelectedIndex = -1;
            this.cbo_Methods.Text = string.Empty;
            if(methods !=null && methods.Length>0)
            {
                foreach(MethodInfo method in methods)
                {
                    this.cbo_Methods.Items.Add(method.Name);
                }
            }
        }

        private void cbo_Assemblies_SelectedIndexChanged(object sender, EventArgs e)
        {
            if(this.cbo_Assemblies.SelectedIndex >=0)
            {
                string assemblyName = this.cbo_Assemblies.SelectedItem.ToString();
                string assemblyFilePath = this._AssemblyFilePaths[assemblyName];
                this.PopulateClasses(assemblyFilePath);
            }
        }

        private void cbo_EvaluatorClasses_SelectedIndexChanged(object sender, EventArgs e)
        {
            if(this.cbo_Assemblies.SelectedIndex>=0 && this.cbo_EvaluatorClasses.SelectedIndex>=0)
            {
                string assemblyName = this.cbo_Assemblies.SelectedItem.ToString();
                string assemblyFilePath = this._AssemblyFilePaths[assemblyName];
                string typeName = this.cbo_EvaluatorClasses.SelectedItem.ToString();
                string typeFullName = this._TypeFullNames[typeName];
                this.PopulateMethods(assemblyFilePath,typeFullName);
            }
        }

        private void btn_OK_Click(object sender, EventArgs e)
        {
            if(this.cbo_Assemblies.SelectedIndex<0)
            {
                MessageBox.Show("Select assembly");
                this.cbo_Assemblies.Focus();
                return;
            }
            this._ClassRule.AssemblyFilePath = this._AssemblyFilePaths[this.cbo_Assemblies.SelectedItem.ToString()];

            if(this.cbo_EvaluatorClasses.SelectedIndex<0)
            {
                MessageBox.Show("Select class");
                this.cbo_EvaluatorClasses.Focus();
                return;
            }
            this._ClassRule.ClassName = this._TypeFullNames[this.cbo_EvaluatorClasses.SelectedItem.ToString()];

            if(this.cbo_Methods.SelectedIndex<0)
            {
                MessageBox.Show("Select method");
                this.cbo_Methods.Focus();
                return;
            }
            this._ClassRule.MethodName = this.cbo_Methods.SelectedItem.ToString();

            if(this.OnRuleConditionUpdated !=null)
            {
                this.OnRuleConditionUpdated(this._OwnerRuleNode, this._Rule, this._ClassRule);
            }
            this.Close();
        }

        private void btn_Cancel_Click(object sender, EventArgs e)
        {
            this.Close();
        }
    }
}
